/*  
*********************************************************************************************************  
*                                                uC/OS-II  
*                                          The Real-Time Kernel  
*                                            TASK MANAGEMENT  
*  
*                          (c) Copyright 1992-2005, Jean J. Labrosse, Weston, FL  
*                                           All Rights Reserved  
*  
* File    : OS_TASK.C  
* By      : Jean J. Labrosse  
* Version : V2.80  
*********************************************************************************************************  
*/   
   
#ifndef  OS_MASTER_FILE   
#include "ucos_ii.h"   
#endif   
   
/*  
*********************************************************************************************************  
*                                        CHANGE PRIORITY OF A TASK  
*  
* Description: This function allows you to change the priority of a task dynamically.  Note that the new  
*              priority MUST be available.  
*  
* Arguments  : oldp     is the old priority  
*  
*              newp     is the new priority  
*  
* Returns    : OS_NO_ERR          is the call was successful  
*              OS_PRIO_INVALID    if the priority you specify is higher that the maximum allowed  
*                                 (i.e. >= OS_LOWEST_PRIO)  
*              OS_PRIO_EXIST      if the new priority already exist.  
*              OS_PRIO_ERR        there is no task with the specified OLD priority (i.e. the OLD task does  
*                                 not exist.  
*              OS_TASK_NOT_EXIST  if the task is assigned to a Mutex PIP.  
*********************************************************************************************************  
*/   
   
#if OS_TASK_CHANGE_PRIO_EN > 0   
INT8U  OSTaskChangePrio (INT8U oldprio, INT8U newprio)   
{   
#if OS_EVENT_EN   
    OS_EVENT    *pevent;   
#endif   
    OS_TCB      *ptcb;   
    INT8U        x;   
    INT8U        y;   
#if OS_LOWEST_PRIO <= 63   
    INT8U        bitx;   
    INT8U        bity;   
#else   
    INT16U       bitx;   
    INT16U       bity;   
#endif   
    INT8U        y_old;   
#if OS_CRITICAL_METHOD == 3   
    OS_CPU_SR    cpu_sr = 0;                                    /* Storage for CPU status register     */   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (oldprio >= OS_LOWEST_PRIO) {   
        if (oldprio != OS_PRIO_SELF) {   
            return (OS_PRIO_INVALID);   
        }   
    }   
    if (newprio >= OS_LOWEST_PRIO) {   
        return (OS_PRIO_INVALID);   
    }   
#endif   
    OS_ENTER_CRITICAL();   
    if (OSTCBPrioTbl[newprio] != (OS_TCB *)0) {                 /* New priority must not already exist */   
        OS_EXIT_CRITICAL();   
        return (OS_PRIO_EXIST);   
    }   
    if (oldprio == OS_PRIO_SELF) {                              /* See if changing self                */   
        oldprio = OSTCBCur->OSTCBPrio;                          /* Yes, get priority                   */   
    }   
    ptcb = OSTCBPrioTbl[oldprio];   
    if (ptcb == (OS_TCB *)0) {                                  /* Does task to change exist?          */   
        OS_EXIT_CRITICAL();                                     /* No, can't change its priority!      */   
        return (OS_PRIO_ERR);   
    }   
    if (ptcb == (OS_TCB *)1) {                                  /* Is task assigned to Mutex           */   
        OS_EXIT_CRITICAL();                                     /* No, can't change its priority!      */   
        return (OS_TASK_NOT_EXIST);   
    }   
#if OS_LOWEST_PRIO <= 63   
    y                     = newprio >> 3;                       /* Yes, compute new TCB fields         */   
    x                     = newprio & 0x07;   
#else   
    y                     = (newprio >> 4) & 0xFF;   
    x                     =  newprio & 0x0F;   
#endif   
   
    bity                  = 1 << y;   
    bitx                  = 1 << x;   
    OSTCBPrioTbl[oldprio] = (OS_TCB *)0;                        /* Remove TCB from old priority        */   
    OSTCBPrioTbl[newprio] = ptcb;                               /* Place pointer to TCB @ new priority */   
    y_old                 = ptcb->OSTCBY;   
    if ((OSRdyTbl[y_old] & ptcb->OSTCBBitX) != 0) {             /* If task is ready make it not        */   
        OSRdyTbl[y_old] &= ~ptcb->OSTCBBitX;   
        if (OSRdyTbl[y_old] == 0) {   
            OSRdyGrp &= ~ptcb->OSTCBBitY;   
        }   
        OSRdyGrp    |= bity;                                    /* Make new priority ready to run      */   
        OSRdyTbl[y] |= bitx;   
#if OS_EVENT_EN   
    } else {                                                    /* Task was not ready ...              */   
        pevent = ptcb->OSTCBEventPtr;   
        if (pevent != (OS_EVENT *)0) {                          /* ... remove from event wait list     */   
            pevent->OSEventTbl[y_old] &= ~ptcb->OSTCBBitX;   
            if (pevent->OSEventTbl[y_old] == 0) {   
                pevent->OSEventGrp &= ~ptcb->OSTCBBitY;   
            }   
            pevent->OSEventGrp    |= bity;                      /* Add new priority to wait list       */   
            pevent->OSEventTbl[y] |= bitx;   
        }   
#endif   
    }   
    ptcb->OSTCBPrio = newprio;                                  /* Set new task priority               */   
    ptcb->OSTCBY    = y;   
    ptcb->OSTCBX    = x;   
    ptcb->OSTCBBitY = bity;   
    ptcb->OSTCBBitX = bitx;   
    OS_EXIT_CRITICAL();   
    OS_Sched();                                                 /* Run highest priority task ready     */   
    return (OS_NO_ERR);   
}   
#endif   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                            CREATE A TASK  
*  
* Description: This function is used to have uC/OS-II manage the execution of a task.  Tasks can either  
*              be created prior to the start of multitasking or by a running task.  A task cannot be  
*              created by an ISR.  
*  
* Arguments  : task     is a pointer to the task's code  
*  
*              p_arg    is a pointer to an optional data area which can be used to pass parameters to  
*                       the task when the task first executes.  Where the task is concerned it thinks  
*                       it was invoked and passed the argument 'p_arg' as follows:  
*  
*                           void Task (void *p_arg)  
*                           {  
*                               for (;;) {  
*                                   Task code;  
*                               }  
*                           }  
*  
*              ptos     is a pointer to the task's top of stack.  If the configuration constant  
*                       OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high  
*                       memory to low memory).  'pstk' will thus point to the highest (valid) memory  
*                       location of the stack.  If OS_STK_GROWTH is set to 0, 'pstk' will point to the  
*                       lowest memory location of the stack and the stack will grow with increasing  
*                       memory locations.  
*  
*              prio     is the task's priority.  A unique priority MUST be assigned to each task and the  
*                       lower the number, the higher the priority.  
*  
* Returns    : OS_NO_ERR               if the function was successful.  
*              OS_PRIO_EXIT            if the task priority already exist  
*                                      (each task MUST have a unique priority).  
*              OS_PRIO_INVALID         if the priority you specify is higher that the maximum allowed  
*                                      (i.e. >= OS_LOWEST_PRIO)  
*              OS_ERR_TASK_CREATE_ISR  if you tried to create a task from an ISR.  
*********************************************************************************************************  
*/   
   
#if OS_TASK_CREATE_EN > 0   
INT8U  OSTaskCreate (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio)   
{   
    OS_STK    *psp;   
    INT8U      err;   
#if OS_CRITICAL_METHOD == 3                  /* Allocate storage for CPU status register               */   
    OS_CPU_SR  cpu_sr = 0;   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (prio > OS_LOWEST_PRIO) {             /* Make sure priority is within allowable range           */   
        return (OS_PRIO_INVALID);   
    }   
#endif   
    OS_ENTER_CRITICAL();   
    if (OSIntNesting > 0) {                  /* Make sure we don't create the task from within an ISR  */   
        OS_EXIT_CRITICAL();   
        return (OS_ERR_TASK_CREATE_ISR);   
    }   
    if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority  */   
        OSTCBPrioTbl[prio] = (OS_TCB *)1;    /* Reserve the priority to prevent others from doing ...  */   
                                             /* ... the same thing until task is created.              */   
        OS_EXIT_CRITICAL();   
        psp = OSTaskStkInit(task, p_arg, ptos, 0);              /* Initialize the task's stack         */   
        err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0);   
        if (err == OS_NO_ERR) {   
            if (OSRunning == TRUE) {         /* Find highest priority task if multitasking has started */   
                OS_Sched();   
            }   
        } else {   
            OS_ENTER_CRITICAL();   
            OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others                 */   
            OS_EXIT_CRITICAL();   
        }   
        return (err);   
    }   
    OS_EXIT_CRITICAL();   
    return (OS_PRIO_EXIST);   
}   
#endif   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                     CREATE A TASK (Extended Version)  
*  
* Description: This function is used to have uC/OS-II manage the execution of a task.  Tasks can either  
*              be created prior to the start of multitasking or by a running task.  A task cannot be  
*              created by an ISR.  This function is similar to OSTaskCreate() except that it allows  
*              additional information about a task to be specified.  
*  
* Arguments  : task      is a pointer to the task's code  
*  
*              p_arg     is a pointer to an optional data area which can be used to pass parameters to  
*                        the task when the task first executes.  Where the task is concerned it thinks  
*                        it was invoked and passed the argument 'p_arg' as follows:  
*  
*                            void Task (void *p_arg)  
*                            {  
*                                for (;;) {  
*                                    Task code;  
*                                }  
*                            }  
*  
*              ptos      is a pointer to the task's top of stack.  If the configuration constant  
*                        OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high  
*                        memory to low memory).  'ptos' will thus point to the highest (valid) memory  
*                        location of the stack.  If OS_STK_GROWTH is set to 0, 'ptos' will point to the  
*                        lowest memory location of the stack and the stack will grow with increasing  
*                        memory locations.  'ptos' MUST point to a valid 'free' data item.  
*  
*              prio      is the task's priority.  A unique priority MUST be assigned to each task and the  
*                        lower the number, the higher the priority.  
*  
*              id        is the task's ID (0..65535)  
*  
*              pbos      is a pointer to the task's bottom of stack.  If the configuration constant  
*                        OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high  
*                        memory to low memory).  'pbos' will thus point to the LOWEST (valid) memory  
*                        location of the stack.  If OS_STK_GROWTH is set to 0, 'pbos' will point to the  
*                        HIGHEST memory location of the stack and the stack will grow with increasing  
*                        memory locations.  'pbos' MUST point to a valid 'free' data item.  
*  
*              stk_size  is the size of the stack in number of elements.  If OS_STK is set to INT8U,  
*                        'stk_size' corresponds to the number of bytes available.  If OS_STK is set to  
*                        INT16U, 'stk_size' contains the number of 16-bit entries available.  Finally, if  
*                        OS_STK is set to INT32U, 'stk_size' contains the number of 32-bit entries  
*                        available on the stack.  
*  
*              pext      is a pointer to a user supplied memory location which is used as a TCB extension.  
*                        For example, this user memory can hold the contents of floating-point registers  
*                        during a context switch, the time each task takes to execute, the number of times  
*                        the task has been switched-in, etc.  
*  
*              opt       contains additional information (or options) about the behavior of the task.  The  
*                        LOWER 8-bits are reserved by uC/OS-II while the upper 8 bits can be application  
*                        specific.  See OS_TASK_OPT_??? in uCOS-II.H.  Current choices are:  
*  
*                        OS_TASK_OPT_STK_CHK      Stack checking to be allowed for the task  
*                        OS_TASK_OPT_STK_CLR      Clear the stack when the task is created  
*                        OS_TASK_OPT_SAVE_FP      If the CPU has floating-point registers, save them  
*                                                 during a context switch.  
*  
* Returns    : OS_NO_ERR               if the function was successful.  
*              OS_PRIO_EXIT            if the task priority already exist  
*                                      (each task MUST have a unique priority).  
*              OS_PRIO_INVALID         if the priority you specify is higher that the maximum allowed  
*                                      (i.e. > OS_LOWEST_PRIO)  
*              OS_ERR_TASK_CREATE_ISR  if you tried to create a task from an ISR.  
*********************************************************************************************************  
*/   
/*$PAGE*/   
#if OS_TASK_CREATE_EXT_EN > 0   
INT8U  OSTaskCreateExt (void   (*task)(void *p_arg),   
                        void    *p_arg,   
                        OS_STK  *ptos,   
                        INT8U    prio,   
                        INT16U   id,   
                        OS_STK  *pbos,   
                        INT32U   stk_size,   
                        void    *pext,   
                        INT16U   opt)   
{   
    OS_STK    *psp;   
    INT8U      err;   
#if OS_CRITICAL_METHOD == 3                  /* Allocate storage for CPU status register               */   
    OS_CPU_SR  cpu_sr = 0;   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (prio > OS_LOWEST_PRIO) {             /* Make sure priority is within allowable range           */   
        return (OS_PRIO_INVALID);   
    }   
#endif   
    OS_ENTER_CRITICAL();   
    if (OSIntNesting > 0) {                  /* Make sure we don't create the task from within an ISR  */   
        OS_EXIT_CRITICAL();   
        return (OS_ERR_TASK_CREATE_ISR);   
    }   
    if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority  */   
        OSTCBPrioTbl[prio] = (OS_TCB *)1;    /* Reserve the priority to prevent others from doing ...  */   
                                             /* ... the same thing until task is created.              */   
        OS_EXIT_CRITICAL();   
   
        OS_TaskStkClr(pbos, stk_size, opt);                    /* Clear the task stack (if needed)     */   
   
        psp = OSTaskStkInit(task, p_arg, ptos, opt);           /* Initialize the task's stack          */   
        err = OS_TCBInit(prio, psp, pbos, id, stk_size, pext, opt);   
        if (err == OS_NO_ERR) {   
            if (OSRunning == TRUE) {                           /* Find HPT if multitasking has started */   
                OS_Sched();   
            }   
        } else {   
            OS_ENTER_CRITICAL();   
            OSTCBPrioTbl[prio] = (OS_TCB *)0;                  /* Make this priority avail. to others  */   
            OS_EXIT_CRITICAL();   
        }   
        return (err);   
    }   
    OS_EXIT_CRITICAL();   
    return (OS_PRIO_EXIST);   
}   
#endif   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                            DELETE A TASK  
*  
* Description: This function allows you to delete a task.  The calling task can delete itself by  
*              its own priority number.  The deleted task is returned to the dormant state and can be  
*              re-activated by creating the deleted task again.  
*  
* Arguments  : prio    is the priority of the task to delete.  Note that you can explicitely delete  
*                      the current task without knowing its priority level by setting 'prio' to  
*                      OS_PRIO_SELF.  
*  
* Returns    : OS_NO_ERR           if the call is successful  
*              OS_TASK_DEL_IDLE    if you attempted to delete uC/OS-II's idle task  
*              OS_PRIO_INVALID     if the priority you specify is higher that the maximum allowed  
*                                  (i.e. >= OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF.  
*              OS_TASK_DEL_ERR     if the task you want to delete does not exist.  
*              OS_TASK_NOT_EXIST   if the task is assigned to a Mutex PIP.  
*              OS_TASK_DEL_ISR     if you tried to delete a task from an ISR  
*  
* Notes      : 1) To reduce interrupt latency, OSTaskDel() 'disables' the task:  
*                    a) by making it not ready  
*                    b) by removing it from any wait lists  
*                    c) by preventing OSTimeTick() from making the task ready to run.  
*                 The task can then be 'unlinked' from the miscellaneous structures in uC/OS-II.  
*              2) The function OS_Dummy() is called after OS_EXIT_CRITICAL() because, on most processors,  
*                 the next instruction following the enable interrupt instruction is ignored.  
*              3) An ISR cannot delete a task.  
*              4) The lock nesting counter is incremented because, for a brief instant, if the current  
*                 task is being deleted, the current task would not be able to be rescheduled because it  
*                 is removed from the ready list.  Incrementing the nesting counter prevents another task  
*                 from being schedule.  This means that an ISR would return to the current task which is  
*                 being deleted.  The rest of the deletion would thus be able to be completed.  
*********************************************************************************************************  
*/   
/*$PAGE*/   
#if OS_TASK_DEL_EN > 0   
INT8U  OSTaskDel (INT8U prio)   
{   
#if OS_EVENT_EN   
    OS_EVENT     *pevent;   
#endif   
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)   
    OS_FLAG_NODE *pnode;   
#endif   
    OS_TCB       *ptcb;   
    INT8U         y;   
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */   
    OS_CPU_SR     cpu_sr = 0;   
#endif   
   
   
   
    if (OSIntNesting > 0) {                                     /* See if trying to delete from ISR    */   
        return (OS_TASK_DEL_ISR);   
    }   
#if OS_ARG_CHK_EN > 0   
    if (prio == OS_IDLE_PRIO) {                                 /* Not allowed to delete idle task     */   
        return (OS_TASK_DEL_IDLE);   
    }   
    if (prio >= OS_LOWEST_PRIO) {                               /* Task priority valid ?               */   
        if (prio != OS_PRIO_SELF) {   
            return (OS_PRIO_INVALID);   
        }   
    }   
#endif   
    OS_ENTER_CRITICAL();   
    if (prio == OS_PRIO_SELF) {                                 /* See if requesting to delete self    */   
        prio = OSTCBCur->OSTCBPrio;                             /* Set priority to delete to current   */   
    }   
    ptcb = OSTCBPrioTbl[prio];   
    if (ptcb == (OS_TCB *)0) {                                  /* Task to delete must exist           */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_DEL_ERR);   
    }   
    if (ptcb == (OS_TCB *)1) {                                  /* Must not be assigned to Mutex       */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_NOT_EXIST);   
    }   
    y            =  ptcb->OSTCBY;   
    OSRdyTbl[y] &= ~ptcb->OSTCBBitX;   
    if (OSRdyTbl[y] == 0) {                                     /* Make task not ready                 */   
        OSRdyGrp &= ~ptcb->OSTCBBitY;   
    }   
#if OS_EVENT_EN   
    pevent = ptcb->OSTCBEventPtr;   
    if (pevent != (OS_EVENT *)0) {                              /* If task is waiting on event         */   
        pevent->OSEventTbl[y] &= ~ptcb->OSTCBBitX;   
        if (pevent->OSEventTbl[y] == 0) {                       /* ... remove task from ...            */   
            pevent->OSEventGrp &= ~ptcb->OSTCBBitY;             /* ... event ctrl block                */   
        }   
    }   
#endif   
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)   
    pnode = ptcb->OSTCBFlagNode;   
    if (pnode != (OS_FLAG_NODE *)0) {                           /* If task is waiting on event flag    */   
        OS_FlagUnlink(pnode);                                   /* Remove from wait list               */   
    }   
#endif   
    ptcb->OSTCBDly    = 0;                                      /* Prevent OSTimeTick() from updating  */   
    ptcb->OSTCBStat   = OS_STAT_RDY;                            /* Prevent task from being resumed     */   
    ptcb->OSTCBPendTO = FALSE;   
    if (OSLockNesting < 255u) {                                 /* Make sure we don't context switch   */   
        OSLockNesting++;   
    }   
    OS_EXIT_CRITICAL();                                         /* Enabling INT. ignores next instruc. */   
    OS_Dummy();                                                 /* ... Dummy ensures that INTs will be */   
    OS_ENTER_CRITICAL();                                        /* ... disabled HERE!                  */   
    if (OSLockNesting > 0) {                                    /* Remove context switch lock          */   
        OSLockNesting--;   
    }   
    OSTaskDelHook(ptcb);                                        /* Call user defined hook              */   
    OSTaskCtr--;                                                /* One less task being managed         */   
    OSTCBPrioTbl[prio] = (OS_TCB *)0;                           /* Clear old priority entry            */   
    if (ptcb->OSTCBPrev == (OS_TCB *)0) {                       /* Remove from TCB chain               */   
        ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0;   
        OSTCBList                  = ptcb->OSTCBNext;   
    } else {   
        ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext;   
        ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev;   
    }   
    ptcb->OSTCBNext   = OSTCBFreeList;                          /* Return TCB to free TCB list         */   
    OSTCBFreeList     = ptcb;   
#if OS_TASK_NAME_SIZE > 1   
    ptcb->OSTCBTaskName[0] = '?';                               /* Unknown name                        */   
    ptcb->OSTCBTaskName[1] = OS_ASCII_NUL;   
#endif   
    OS_EXIT_CRITICAL();   
    OS_Sched();                                                 /* Find new highest priority task      */   
    return (OS_NO_ERR);   
}   
#endif   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                    REQUEST THAT A TASK DELETE ITSELF  
*  
* Description: This function is used to:  
*                   a) notify a task to delete itself.  
*                   b) to see if a task requested that the current task delete itself.  
*              This function is a little tricky to understand.  Basically, you have a task that needs  
*              to be deleted however, this task has resources that it has allocated (memory buffers,  
*              semaphores, mailboxes, queues etc.).  The task cannot be deleted otherwise these  
*              resources would not be freed.  The requesting task calls OSTaskDelReq() to indicate that  
*              the task needs to be deleted.  Deleting of the task is however, deferred to the task to  
*              be deleted.  For example, suppose that task #10 needs to be deleted.  The requesting task  
*              example, task #5, would call OSTaskDelReq(10).  When task #10 gets to execute, it calls  
*              this function by specifying OS_PRIO_SELF and monitors the returned value.  If the return  
*              value is OS_TASK_DEL_REQ, another task requested a task delete.  Task #10 would look like  
*              this:  
*  
*                   void Task(void *p_arg)  
*                   {  
*                       .  
*                       .  
*                       while (1) {  
*                           OSTimeDly(1);  
*                           if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) {  
*                               Release any owned resources;  
*                               De-allocate any dynamic memory;  
*                               OSTaskDel(OS_PRIO_SELF);  
*                           }  
*                       }  
*                   }  
*  
* Arguments  : prio    is the priority of the task to request the delete from  
*  
* Returns    : OS_NO_ERR          if the task exist and the request has been registered  
*              OS_TASK_NOT_EXIST  if the task has been deleted.  This allows the caller to know whether  
*                                 the request has been executed.  
*              OS_TASK_DEL_ERR    if the task is assigned to a Mutex.  
*              OS_TASK_DEL_IDLE   if you requested to delete uC/OS-II's idle task  
*              OS_PRIO_INVALID    if the priority you specify is higher that the maximum allowed  
*                                 (i.e. >= OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF.  
*              OS_TASK_DEL_REQ    if a task (possibly another task) requested that the running task be  
*                                 deleted.  
*********************************************************************************************************  
*/   
/*$PAGE*/   
#if OS_TASK_DEL_EN > 0   
INT8U  OSTaskDelReq (INT8U prio)   
{   
    INT8U      stat;   
    OS_TCB    *ptcb;   
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */   
    OS_CPU_SR  cpu_sr = 0;   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (prio == OS_IDLE_PRIO) {                                 /* Not allowed to delete idle task     */   
        return (OS_TASK_DEL_IDLE);   
    }   
    if (prio >= OS_LOWEST_PRIO) {                                /* Task priority valid ?               */   
        if (prio != OS_PRIO_SELF) {   
            return (OS_PRIO_INVALID);   
        }   
    }   
#endif   
    if (prio == OS_PRIO_SELF) {                                 /* See if a task is requesting to ...  */   
        OS_ENTER_CRITICAL();                                    /* ... this task to delete itself      */   
        stat = OSTCBCur->OSTCBDelReq;                           /* Return request status to caller     */   
        OS_EXIT_CRITICAL();   
        return (stat);   
    }   
    OS_ENTER_CRITICAL();   
    ptcb = OSTCBPrioTbl[prio];   
    if (ptcb == (OS_TCB *)0) {                                  /* Task to delete must exist           */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_NOT_EXIST);                             /* Task must already be deleted        */   
    }   
    if (ptcb == (OS_TCB *)1) {                                  /* Must NOT be assigned to a Mutex     */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_DEL_ERR);   
    }   
    ptcb->OSTCBDelReq = OS_TASK_DEL_REQ;                        /* Set flag indicating task to be DEL. */   
    OS_EXIT_CRITICAL();   
    return (OS_NO_ERR);   
}   
#endif   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                        GET THE NAME OF A TASK  
*  
* Description: This function is called to obtain the name of a task.  
*  
* Arguments  : prio      is the priority of the task that you want to obtain the name from.  
*  
*              pname     is a pointer to an ASCII string that will receive the name of the task.  The  
*                        string must be able to hold at least OS_TASK_NAME_SIZE characters.  
*  
*              err       is a pointer to an error code that can contain one of the following values:  
*  
*                        OS_NO_ERR                  if the requested task is resumed  
*                        OS_TASK_NOT_EXIST          if the task has not been created or is assigned to a Mutex  
*                        OS_PRIO_INVALID            if you specified an invalid priority:  
*                                                   A higher value than the idle task or not OS_PRIO_SELF.  
*                        OS_ERR_PNAME_NULL          You passed a NULL pointer for 'pname'  
*  
* Returns    : The length of the string or 0 if the task does not exist.  
*********************************************************************************************************  
*/   
   
#if OS_TASK_NAME_SIZE > 1   
INT8U  OSTaskNameGet (INT8U prio, INT8U *pname, INT8U *err)   
{   
    OS_TCB    *ptcb;   
    INT8U      len;   
#if OS_CRITICAL_METHOD == 3                              /* Allocate storage for CPU status register   */   
    OS_CPU_SR  cpu_sr = 0;   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (err == (INT8U *)0) {                             /* Validate 'err'                             */   
        return (0);   
    }   
    if (prio > OS_LOWEST_PRIO) {                         /* Task priority valid ?                      */   
        if (prio != OS_PRIO_SELF) {   
            *err = OS_PRIO_INVALID;                      /* No                                         */   
            return (0);   
        }   
    }   
    if (pname == (INT8U *)0) {                             /* Is 'pname' a NULL pointer?                */   
        *err = OS_ERR_PNAME_NULL;                         /* Yes                                       */   
        return (0);   
    }   
#endif   
    OS_ENTER_CRITICAL();   
    if (prio == OS_PRIO_SELF) {                           /* See if caller desires it's own name       */   
        prio = OSTCBCur->OSTCBPrio;   
    }   
    ptcb = OSTCBPrioTbl[prio];   
    if (ptcb == (OS_TCB *)0) {                            /* Does task exist?                          */   
        OS_EXIT_CRITICAL();                               /* No                                        */   
        *err = OS_TASK_NOT_EXIST;   
        return (0);   
    }   
    if (ptcb == (OS_TCB *)1) {                            /* Task assigned to a Mutex?                 */   
        OS_EXIT_CRITICAL();                               /* Yes                                       */   
        *err = OS_TASK_NOT_EXIST;   
        return (0);   
    }   
    len  = OS_StrCopy(pname, ptcb->OSTCBTaskName);        /* Yes, copy name from TCB                   */   
    OS_EXIT_CRITICAL();   
    *err = OS_NO_ERR;   
    return (len);   
}   
#endif   
   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                        ASSIGN A NAME TO A TASK  
*  
* Description: This function is used to set the name of a task.  
*  
* Arguments  : prio      is the priority of the task that you want the assign a name to.  
*  
*              pname     is a pointer to an ASCII string that contains the name of the task.  The ASCII  
*                        string must be NUL terminated.  
*  
*              err       is a pointer to an error code that can contain one of the following values:  
*  
*                        OS_NO_ERR                  if the requested task is resumed  
*                        OS_TASK_NOT_EXIST          if the task has not been created or is assigned to a Mutex  
*                        OS_ERR_TASK_NAME_TOO_LONG  if the name you are giving to the task exceeds the  
*                                                   storage capacity of a task name as specified by  
*                                                   OS_TASK_NAME_SIZE.  
*                        OS_ERR_PNAME_NULL          You passed a NULL pointer for 'pname'  
*                        OS_PRIO_INVALID            if you specified an invalid priority:  
*                                                   A higher value than the idle task or not OS_PRIO_SELF.  
*  
* Returns    : None  
*********************************************************************************************************  
*/   
#if OS_TASK_NAME_SIZE > 1   
void  OSTaskNameSet (INT8U prio, INT8U *pname, INT8U *err)   
{   
    INT8U      len;   
    OS_TCB    *ptcb;   
#if OS_CRITICAL_METHOD == 3                          /* Allocate storage for CPU status register       */   
    OS_CPU_SR  cpu_sr = 0;   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (err == (INT8U *)0) {                         /* Validate 'err'                                 */   
        return;   
    }   
    if (prio > OS_LOWEST_PRIO) {                     /* Task priority valid ?                          */   
        if (prio != OS_PRIO_SELF) {   
            *err = OS_PRIO_INVALID;                  /* No                                             */   
            return;   
        }   
    }   
    if (pname == (INT8U *)0) {                        /* Is 'pname' a NULL pointer?                     */   
        *err = OS_ERR_PNAME_NULL;                    /* Yes                                            */   
        return;   
    }   
#endif   
    OS_ENTER_CRITICAL();   
    if (prio == OS_PRIO_SELF) {                      /* See if caller desires to set it's own name     */   
        prio = OSTCBCur->OSTCBPrio;   
    }   
    ptcb = OSTCBPrioTbl[prio];   
    if (ptcb == (OS_TCB *)0) {                       /* Does task exist?                               */   
        OS_EXIT_CRITICAL();                          /* No                                             */   
        *err = OS_TASK_NOT_EXIST;   
        return;   
    }   
    if (ptcb == (OS_TCB *)1) {                       /* Task assigned to a Mutex?                      */   
        OS_EXIT_CRITICAL();                          /* Yes                                            */   
        *err = OS_TASK_NOT_EXIST;   
        return;   
    }   
    len = OS_StrLen(pname);                          /* Yes, Can we fit the string in the TCB?         */   
    if (len > (OS_TASK_NAME_SIZE - 1)) {             /*      No                                        */   
        OS_EXIT_CRITICAL();   
        *err = OS_ERR_TASK_NAME_TOO_LONG;   
        return;   
    }   
    (void)OS_StrCopy(ptcb->OSTCBTaskName, pname);    /*      Yes, copy to TCB                          */   
    OS_EXIT_CRITICAL();   
    *err = OS_NO_ERR;   
}   
#endif   
   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                        RESUME A SUSPENDED TASK  
*  
* Description: This function is called to resume a previously suspended task.  This is the only call that  
*              will remove an explicit task suspension.  
*  
* Arguments  : prio     is the priority of the task to resume.  
*  
* Returns    : OS_NO_ERR                if the requested task is resumed  
*              OS_PRIO_INVALID          if the priority you specify is higher that the maximum allowed  
*                                       (i.e. >= OS_LOWEST_PRIO)  
*              OS_TASK_RESUME_PRIO      if the task to resume does not exist  
*              OS_TASK_NOT_EXIST        if the task is assigned to a Mutex PIP  
*              OS_TASK_NOT_SUSPENDED    if the task to resume has not been suspended  
*********************************************************************************************************  
*/   
   
#if OS_TASK_SUSPEND_EN > 0   
INT8U  OSTaskResume (INT8U prio)   
{   
    OS_TCB    *ptcb;   
#if OS_CRITICAL_METHOD == 3                                   /* Storage for CPU status register       */   
    OS_CPU_SR  cpu_sr = 0;   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (prio >= OS_LOWEST_PRIO) {                             /* Make sure task priority is valid      */   
        return (OS_PRIO_INVALID);   
    }   
#endif   
    OS_ENTER_CRITICAL();   
    ptcb = OSTCBPrioTbl[prio];   
    if (ptcb == (OS_TCB *)0) {                                /* Task to suspend must exist            */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_RESUME_PRIO);   
    }   
    if (ptcb == (OS_TCB *)1) {                                /* See if assigned to Mutex              */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_NOT_EXIST);   
    }   
    if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) != OS_STAT_RDY) { /* Task must be suspended                */   
        ptcb->OSTCBStat &= ~OS_STAT_SUSPEND;               /* Remove suspension                     */   
        if (ptcb->OSTCBStat == OS_STAT_RDY) {                 /* See if task is now ready              */   
            if (ptcb->OSTCBDly == 0) {   
                OSRdyGrp               |= ptcb->OSTCBBitY;    /* Yes, Make task ready to run           */   
                OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;   
                OS_EXIT_CRITICAL();   
                OS_Sched();   
            } else {   
                OS_EXIT_CRITICAL();   
            }   
        } else {                                              /* Must be pending on event              */   
            OS_EXIT_CRITICAL();   
        }   
        return (OS_NO_ERR);   
    }   
    OS_EXIT_CRITICAL();   
    return (OS_TASK_NOT_SUSPENDED);   
}   
#endif   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                             STACK CHECKING  
*  
* Description: This function is called to check the amount of free memory left on the specified task's  
*              stack.  
*  
* Arguments  : prio          is the task priority  
*  
*              p_stk_data    is a pointer to a data structure of type OS_STK_DATA.  
*  
* Returns    : OS_NO_ERR           upon success  
*              OS_PRIO_INVALID     if the priority you specify is higher that the maximum allowed  
*                                  (i.e. > OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF.  
*              OS_TASK_NOT_EXIST   if the desired task has not been created or is assigned to a Mutex PIP  
*              OS_TASK_OPT_ERR     if you did NOT specified OS_TASK_OPT_STK_CHK when the task was created  
*              OS_ERR_PDATA_NULL   if 'p_stk_data' is a NULL pointer  
*********************************************************************************************************  
*/   
#if OS_TASK_CREATE_EXT_EN > 0   
INT8U  OSTaskStkChk (INT8U prio, OS_STK_DATA *p_stk_data)   
{   
    OS_TCB    *ptcb;   
    OS_STK    *pchk;   
    INT32U     free;   
    INT32U     size;   
#if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */   
    OS_CPU_SR  cpu_sr = 0;   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (prio > OS_LOWEST_PRIO) {                       /* Make sure task priority is valid             */   
        if (prio != OS_PRIO_SELF) {   
            return (OS_PRIO_INVALID);   
        }   
    }   
    if (p_stk_data == (OS_STK_DATA *)0) {              /* Validate 'p_stk_data'                        */   
        return (OS_ERR_PDATA_NULL);   
    }   
#endif   
    p_stk_data->OSFree = 0;                            /* Assume failure, set to 0 size                */   
    p_stk_data->OSUsed = 0;   
    OS_ENTER_CRITICAL();   
    if (prio == OS_PRIO_SELF) {                        /* See if check for SELF                        */   
        prio = OSTCBCur->OSTCBPrio;   
    }   
    ptcb = OSTCBPrioTbl[prio];   
    if (ptcb == (OS_TCB *)0) {                         /* Make sure task exist                         */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_NOT_EXIST);   
    }   
    if (ptcb == (OS_TCB *)1) {   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_NOT_EXIST);   
    }   
    if ((ptcb->OSTCBOpt & OS_TASK_OPT_STK_CHK) == 0) { /* Make sure stack checking option is set       */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_OPT_ERR);   
    }   
    free = 0;   
    size = ptcb->OSTCBStkSize;   
    pchk = ptcb->OSTCBStkBottom;   
    OS_EXIT_CRITICAL();   
#if OS_STK_GROWTH == 1   
    while (*pchk++ == (OS_STK)0) {                    /* Compute the number of zero entries on the stk */   
        free++;   
    }   
#else   
    while (*pchk-- == (OS_STK)0) {   
        free++;   
    }   
#endif   
    p_stk_data->OSFree = free * sizeof(OS_STK);           /* Compute number of free bytes on the stack */   
    p_stk_data->OSUsed = (size - free) * sizeof(OS_STK);  /* Compute number of bytes used on the stack */   
    return (OS_NO_ERR);   
}   
#endif   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                            SUSPEND A TASK  
*  
* Description: This function is called to suspend a task.  The task can be the calling task if the  
*              priority passed to OSTaskSuspend() is the priority of the calling task or OS_PRIO_SELF.  
*  
* Arguments  : prio     is the priority of the task to suspend.  If you specify OS_PRIO_SELF, the  
*                       calling task will suspend itself and rescheduling will occur.  
*  
* Returns    : OS_NO_ERR                if the requested task is suspended  
*              OS_TASK_SUSPEND_IDLE     if you attempted to suspend the idle task which is not allowed.  
*              OS_PRIO_INVALID          if the priority you specify is higher that the maximum allowed  
*                                       (i.e. >= OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF.  
*              OS_TASK_SUSPEND_PRIO     if the task to suspend does not exist  
*              OS_TASK_NOT_EXITS        if the task is assigned to a Mutex PIP  
*  
* Note       : You should use this function with great care.  If you suspend a task that is waiting for  
*              an event (i.e. a message, a semaphore, a queue ...) you will prevent this task from  
*              running when the event arrives.  
*********************************************************************************************************  
*/   
   
//#if OS_TASK_SUSPEND_EN > 0   
INT8U  OSTaskSuspend (INT8U prio)   
{   
    BOOLEAN    self;   
    OS_TCB    *ptcb;   
    INT8U      y;   
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */   
    OS_CPU_SR  cpu_sr = 0;   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (prio == OS_IDLE_PRIO) {                                 /* Not allowed to suspend idle task    */   
        return (OS_TASK_SUSPEND_IDLE);   
    }   
    if (prio >= OS_LOWEST_PRIO) {                                /* Task priority valid ?               */   
        if (prio != OS_PRIO_SELF) {   
            return (OS_PRIO_INVALID);   
        }   
    }   
#endif   
    OS_ENTER_CRITICAL();   
    if (prio == OS_PRIO_SELF) {                                 /* See if suspend SELF                 */   
        prio = OSTCBCur->OSTCBPrio;   
        self = TRUE;   
    } else if (prio == OSTCBCur->OSTCBPrio) {                   /* See if suspending self              */   
        self = TRUE;   
    } else {   
        self = FALSE;                                           /* No suspending another task          */   
    }   
    ptcb = OSTCBPrioTbl[prio];   
    if (ptcb == (OS_TCB *)0) {                                  /* Task to suspend must exist          */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_SUSPEND_PRIO);   
    }   
    if (ptcb == (OS_TCB *)1) {                                  /* See if assigned to Mutex            */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_NOT_EXIST);   
    }   
    y            = ptcb->OSTCBY;   
    OSRdyTbl[y] &= ~ptcb->OSTCBBitX;                         /* Make task not ready                 */   
    if (OSRdyTbl[y] == 0) {   
        OSRdyGrp &= ~ptcb->OSTCBBitY;   
    }   
    ptcb->OSTCBStat |= OS_STAT_SUSPEND;                         /* Status of task is 'SUSPENDED'       */   
    OS_EXIT_CRITICAL();   
    if (self == TRUE) {                                         /* Context switch only if SELF         */   
        OS_Sched();   
    }   
    return (OS_NO_ERR);   
}   
//#endif   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                            QUERY A TASK  
*  
* Description: This function is called to obtain a copy of the desired task's TCB.  
*  
* Arguments  : prio         is the priority of the task to obtain information from.  
*  
*              p_task_data  is a pointer to where the desired task's OS_TCB will be stored.  
*  
* Returns    : OS_NO_ERR          if the requested task is suspended  
*              OS_PRIO_INVALID    if the priority you specify is higher that the maximum allowed  
*                                 (i.e. > OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF.  
*              OS_PRIO_ERR        if the desired task has not been created  
*              OS_TASK_NOT_EXIST  if the task is assigned to a Mutex PIP  
*              OS_ERR_PDATA_NULL  if 'p_task_data' is a NULL pointer  
*********************************************************************************************************  
*/   
   
#if OS_TASK_QUERY_EN > 0   
INT8U  OSTaskQuery (INT8U prio, OS_TCB *p_task_data)   
{   
    OS_TCB    *ptcb;   
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */   
    OS_CPU_SR  cpu_sr = 0;   
#endif   
   
   
   
#if OS_ARG_CHK_EN > 0   
    if (prio > OS_LOWEST_PRIO) {              /* Task priority valid ?                              */   
        if (prio != OS_PRIO_SELF) {   
            return (OS_PRIO_INVALID);   
        }   
    }   
    if (p_task_data == (OS_TCB *)0) {            /* Validate 'p_task_data'                             */   
        return (OS_ERR_PDATA_NULL);   
    }   
#endif   
    OS_ENTER_CRITICAL();   
    if (prio == OS_PRIO_SELF) {                  /* See if suspend SELF                                */   
        prio = OSTCBCur->OSTCBPrio;   
    }   
    ptcb = OSTCBPrioTbl[prio];   
    if (ptcb == (OS_TCB *)0) {                   /* Task to query must exist                           */   
        OS_EXIT_CRITICAL();   
        return (OS_PRIO_ERR);   
    }   
    if (ptcb == (OS_TCB *)1) {                   /* Task to query must not be assigned to a Mutex      */   
        OS_EXIT_CRITICAL();   
        return (OS_TASK_NOT_EXIST);   
    }   
                                                 /* Copy TCB into user storage area                    */   
    OS_MemCopy((INT8U *)p_task_data, (INT8U *)ptcb, sizeof(OS_TCB));   
    OS_EXIT_CRITICAL();   
    return (OS_NO_ERR);   
}   
#endif   
/*$PAGE*/   
/*  
*********************************************************************************************************  
*                                        CLEAR TASK STACK  
*  
* Description: This function is used to clear the stack of a task (i.e. write all zeros)  
*  
* Arguments  : pbos     is a pointer to the task's bottom of stack.  If the configuration constant  
*                       OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high  
*                       memory to low memory).  'pbos' will thus point to the lowest (valid) memory  
*                       location of the stack.  If OS_STK_GROWTH is set to 0, 'pbos' will point to the  
*                       highest memory location of the stack and the stack will grow with increasing  
*                       memory locations.  'pbos' MUST point to a valid 'free' data item.  
*  
*              size     is the number of 'stack elements' to clear.  
*  
*              opt      contains additional information (or options) about the behavior of the task.  The  
*                       LOWER 8-bits are reserved by uC/OS-II while the upper 8 bits can be application  
*                       specific.  See OS_TASK_OPT_??? in uCOS-II.H.  
*  
* Returns    : none  
*********************************************************************************************************  
*/   
#if OS_TASK_CREATE_EXT_EN > 0   
void  OS_TaskStkClr (OS_STK *pbos, INT32U size, INT16U opt)   
{   
    if ((opt & OS_TASK_OPT_STK_CHK) != 0x0000) {       /* See if stack checking has been enabled       */   
        if ((opt & OS_TASK_OPT_STK_CLR) != 0x0000) {   /* See if stack needs to be cleared             */   
#if OS_STK_GROWTH == 1   
            while (size > 0) {                         /* Stack grows from HIGH to LOW memory          */   
                size--;   
                *pbos++ = (OS_STK)0;                   /* Clear from bottom of stack and up!           */   
            }   
#else   
            while (size > 0) {                         /* Stack grows from LOW to HIGH memory          */   
                size--;   
                *pbos-- = (OS_STK)0;                   /* Clear from bottom of stack and down          */   
            }   
#endif   
        }   
    }   
}   
   
#endif   

